<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>GSAP 横向分屏滚动 + 导航</title>
  <style>
    * { box-sizing: border-box; margin:0; padding:0; }
    html,body { height:100%; overflow:hidden; font-family: sans-serif; }
    .viewport { height: 100vh; width:100%; overflow:hidden; position:relative; }
    .panels {
      display: flex; height: 100%; will-change: transform;
    }
    .panel {
      flex: 0 0 100vw; height: 100%;
      display:flex; align-items:center; justify-content:center;
      color:#fff; font-size:3.2rem; font-weight:700;
      position: relative;
    }
    .panel .content { will-change: opacity, transform; text-align:center; }
    .panel:nth-child(1){ background: linear-gradient(90deg,#2c8ed9,#1d6fb0); }
    .panel:nth-child(2){ background: linear-gradient(90deg,#e05244,#c23b2f); }
    .panel:nth-child(3){ background: linear-gradient(90deg,#2fb86f,#1f8a50); }
    .panel:nth-child(4){ background: linear-gradient(90deg,#8b5fd3,#6c3fb0); }

    /* 小圆点导航 */
    .nav-dots {
      position: fixed;
      right: 20px;
      top: 50%;
      transform: translateY(-50%);
      display: flex;
      flex-direction: column;
      gap: 12px;
      z-index: 1000;
    }
    .nav-dots button {
      width: 12px; height: 12px;
      border-radius: 50%;
      border: none;
      background: rgba(255,255,255,0.5);
      cursor: pointer;
      transition: background 0.3s, transform 0.3s;
    }
    .nav-dots button.active {
      background: #fff;
      transform: scale(1.3);
    }
  </style>
</head>
<body>
  <div class="viewport">
    <div class="panels">
      <section class="panel"><div class="content">SCREEN 1</div></section>
      <section class="panel"><div class="content">SCREEN 2</div></section>
      <section class="panel"><div class="content">SCREEN 3</div></section>
      <section class="panel"><div class="content">SCREEN 4</div></section>
    </div>
  </div>

  <!-- 小圆点导航 -->
  <div class="nav-dots"></div>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/gsap.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/Observer.min.js"></script>
  <script>
    gsap.registerPlugin(Observer);

    const panels = Array.from(document.querySelectorAll('.panel'));
    const panelsWrap = document.querySelector('.panels');
    const contents = panels.map(p => p.querySelector('.content') || p);
    const dotsContainer = document.querySelector('.nav-dots');

    let currentIndex = 0;
    let isAnimating = false;
    const LOCK_MS = 1000; // 单次切换锁定

    // 生成导航按钮
    panels.forEach((_, i) => {
      const btn = document.createElement('button');
      if (i === 0) btn.classList.add('active');
      btn.addEventListener('click', () => goTo(i));
      dotsContainer.appendChild(btn);
    });
    const dots = Array.from(dotsContainer.querySelectorAll('button'));

    // 初始化
    contents.forEach((c, i) => {
      if (i === 0) gsap.set(c, { opacity: 1, x: 0 });
      else gsap.set(c, { opacity: 0, x: 50 });
    });
    gsap.set(panelsWrap, { x: 0 });

    function updateDots(index) {
      dots.forEach((d, i) => d.classList.toggle('active', i === index));
    }

    function goTo(rawIndex) {
      const index = Math.max(0, Math.min(rawIndex, panels.length - 1));
      if (index === currentIndex || isAnimating) return;

      isAnimating = true;
      const fromContent = contents[currentIndex];
      const toContent = contents[index];
      const vw = window.innerWidth;

      const tl = gsap.timeline({ defaults: { ease: "power1.out" } });
      tl.to(fromContent, { opacity: 0, x: -50, duration: 0.55 });
      tl.to(panelsWrap, { x: -index * vw, duration: 0.9, ease: "power2.inOut" }, "<0.05");
      tl.fromTo(toContent, { opacity: 0, x: 50 }, { opacity: 1, x: 0, duration: 0.7 }, "-=0.45");
      tl.call(() => {
        currentIndex = index;
        updateDots(index);
        setTimeout(() => { isAnimating = false; }, LOCK_MS);
      });
    }

    // Observer 捕捉滚轮 + 触摸
    Observer.create({
      target: window,
      type: "wheel,touch,pointer",
      tolerance: 10,
      preventDefault: true,
      passive: false,
      // 鼠标滚轮纵向时，用 onDown/onUp 控制左右翻页
      onDown: () => goTo(currentIndex + 1),
      onUp:   () => goTo(currentIndex - 1),
      onRight: () => goTo(currentIndex + 1),
      onLeft:  () => goTo(currentIndex - 1),
    });

    // 键盘支持
    window.addEventListener('keydown', (e) => {
      if (isAnimating) return;
      if (e.key === 'ArrowRight' || e.key === 'PageDown') { e.preventDefault(); goTo(currentIndex + 1); }
      else if (e.key === 'ArrowLeft' || e.key === 'PageUp') { e.preventDefault(); goTo(currentIndex - 1); }
      else if (e.key === 'Home') { e.preventDefault(); goTo(0); }
      else if (e.key === 'End') { e.preventDefault(); goTo(panels.length - 1); }
    });

    // 窗口缩放时，保证在正确位置
    let raf;
    window.addEventListener('resize', () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const vw = window.innerWidth;
        gsap.set(panelsWrap, { x: -currentIndex * vw });
      });
    });
  </script>
</body>
</html>
